﻿namespace Cellfish.Toolbox.Facts.TaskSchedulers
{
    using System;
    using System.Threading;
    using System.Threading.Tasks;

    using Cellfish.Test;
    using Cellfish.Toolbox.Tasks;
    using Cellfish.Toolbox.TaskSchedulers;

    using Microsoft.VisualStudio.TestTools.UnitTesting;

    [TestClass]
    public class PrivateThreadPoolTaskSchedulerFacts
    {
        private PrivateThreadPoolTaskScheduler scheduler = null;

        [TestCleanup]
        public void Cleanup()
        {
            if (this.scheduler != null)
            {
                this.scheduler.Shutdown(TimeSpan.FromSeconds(5));
                this.scheduler.Dispose();
            }
        }

        [TestMethod]
        public void When_creating_PrivateThreadPoolTaskScheduler_with_zero_threads_Then_ArgumentOutOfRangeException_is_thrown()
        {
            Ensure.Throws<ArgumentOutOfRangeException>(() => new PrivateThreadPoolTaskScheduler(0));
        }

        [TestMethod]
        public void When_creating_PrivateThreadPoolTaskScheduler_with_more_than_100_threads_per_core_Then_ArgumentOutOfRangeException_is_thrown()
        {
            Ensure.Throws<ArgumentOutOfRangeException>(() => new PrivateThreadPoolTaskScheduler(Environment.ProcessorCount * 100 + 1));
        }

        [TestMethod]
        public void When_creating_PrivateThreadPoolTaskScheduler_with_no_argument_Then_max_concurrency_is_CPU_count()
        {
            this.scheduler = new PrivateThreadPoolTaskScheduler();
            Assert.AreEqual(Environment.ProcessorCount, this.scheduler.MaximumConcurrencyLevel);
        }

        [TestMethod]
        public void Given_shut_down_PrivateThreadPoolTaskScheduler_When_starting_new_tasks_then_TaskSchedulerException_is_thrown()
        {
            this.scheduler = new PrivateThreadPoolTaskScheduler();
            var factory = new TaskFactory(this.scheduler);
            this.scheduler.Shutdown(TimeSpan.Zero);
            Ensure.Throws<TaskSchedulerException>(() => factory.StartNew(() => { }));
        }
    }
}
